package com.cfweb.api;

import java.io.File;
import java.io.FileInputStream;
import java.net.URL;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpSession;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.ContentBody;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.apache.james.mime4j.util.CharsetUtil;
import org.apache.log4j.Logger;

import com.cfweb.controller.LoginHandler;
import com.cfweb.exception.CloudFoundryApiException;
import com.cfweb.util.CloudFoundryClientUtil;
import com.cfweb.util.HttpStatusUtil;
import com.cfweb.util.JsonUtil;

public class BuildPackApi {
	
	static Logger logger = Logger.getLogger(BuildPackApi.class);
	
	/**
	 * create buildpack and upload buildpack zip
	 * only zip archive is allowed
	 * @param name
	 * @param path
	 * @param position
	 * @param session
	 * @return
	 * @throws Exception 
	 */
	public static Map<String, Object> createBuildpack(String name, File file, int position, HttpSession session) throws Exception {
		String guid = create_buildpack(name, position, session);
		Map<String, Object> reMap = upload_buildpack(guid, file, session);
		return reMap;
	}
	

	/**
     * create buildpack
     * @param name
     * @param position
     * @param session
     * @return
     * @throws Exception 
     */
	@SuppressWarnings("unchecked")
	private static String create_buildpack(String name, int position, HttpSession session) throws Exception {
		// TODO Auto-generated method stub
		String guid = null;
		HttpClient httpClient = null;
		HttpPost httpPost = null;
		try {
			String url = ((URL) session.getAttribute(LoginHandler.TARGET)).toString() + "/v2/buildpacks?async=true";
			httpClient =  new DefaultHttpClient();
			httpPost = new HttpPost(url);
			String body = "{\"name\":\"" + name + "\",\"position\":" + position + "}";	
			HttpEntity postEntity = new StringEntity(body , "UTF-8");
			httpPost.setEntity(postEntity);
			CloudFoundryClientUtil.setAccessHeaders(httpPost, session);
			HttpResponse response = httpClient.execute(httpPost);
			HttpEntity entity = response.getEntity();  
			String content = EntityUtils.toString(entity, "UTF-8"); 
			Map<String, Object> resMap = JsonUtil.convertJsonToMap(content);
			if (!HttpStatusUtil.isSuccessStatus(response.getStatusLine().getStatusCode())) {
				throw new CloudFoundryApiException(response.getStatusLine().getStatusCode(),  (String) resMap.get("description"));
			}
			guid = (String) ((Map<String, Object>) resMap.get("metadata")).get("guid");
		} catch (Exception e) {
			logger.error(e);
		 	throw(e);
		} finally {
			httpPost.abort();
			httpClient.getConnectionManager().shutdown();
		}
		return guid;
	}
	

	/**
     * upload buildpack
     * only zip archive is allowed
     * @param guid
     * @param file
     * @param session
     * @return status
     * @throws Exception 
     */
	private static Map<String, Object> upload_buildpack(String guid, File file, HttpSession session) throws Exception {
		// TODO Auto-generated method stub
		Map<String, Object> resMap = null;
		HttpClient httpClient = null;
		HttpPut httpPut = null;
		if (guid.isEmpty()) {
			throw new Exception("The guid of buildpack can not be null ! This means the buildpack does not created successfully.");
		}
		try {
			String urlPath = ((URL) session.getAttribute(LoginHandler.TARGET)).toString() + "/v2/buildpacks/" + guid + "/bits";
			
			httpClient =  new DefaultHttpClient();
			httpPut = new HttpPut(urlPath);
			MultipartEntity mpe = new MultipartEntity(
					HttpMultipartMode.BROWSER_COMPATIBLE, null,
					CharsetUtil.UTF_8);
			
			ContentBody filebody = new FileBody(file, "zip");
			mpe.addPart("buildpack", filebody);
			CloudFoundryClientUtil.setAccessHeaders(httpPut, session);
			httpPut.setEntity(mpe);
			
			HttpResponse response = httpClient.execute(httpPut);
			if (!HttpStatusUtil.isSuccessStatus(response.getStatusLine().getStatusCode())) {
				HttpEntity entity = response.getEntity();  
				String content = EntityUtils.toString(entity, "UTF-8"); 
				Map<String, Object> data = JsonUtil.convertJsonToMap(content);
				throw new CloudFoundryApiException(response.getStatusLine().getStatusCode(), (String) data.get("description"));
			}
			resMap = JsonUtil.convertJsonToMap(EntityUtils.toString(response.getEntity()));
			if(resMap != null) {
				resMap.put("status", "ok");
			}
		} catch (Exception e) {
			throw(e);
		} finally {
			httpPut.abort(); 
	        httpClient.getConnectionManager().shutdown();
		}
		return resMap;
	}	
	
	/**
     * update buildpack
     * @param buildpack
     * @param file
     * @param session
     * @return boolean
     * @throws Exception 
     */
	public static boolean update_buildpack(HttpSession session, String buildpack,
			File file) throws Exception {
		HttpClient httpClient = null;
		HttpPut httpPut = null;
		String guid;
		guid = get_buildpack_id(session, buildpack);
		if (guid.isEmpty()) {
			file.delete();
			return false;
		}
		try {
			String host = ((URL) session.getAttribute(LoginHandler.TARGET)).toString();
			String urlPath = host + "/v2/buildpacks/" + guid + "/bits";
			
			httpClient =  new DefaultHttpClient();
			httpPut = new HttpPut(urlPath);
			CloudFoundryClientUtil.setAccessHeaders(httpPut, session);
			/*httpPut.addHeader(HttpHeaders.HOST,"api.local.lai");
			httpPut.addHeader(HttpHeaders.AUTHORIZATION, token);
			httpPut.addHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON);
			httpPut.addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED);*/
			HttpEntity putEntity = new InputStreamEntity(new FileInputStream(file), file.length());
			httpPut.setEntity(putEntity);
			HttpResponse response = httpClient.execute(httpPut);
			if (!HttpStatusUtil.isSuccessStatus(response.getStatusLine().getStatusCode())) {
				file.delete();
				HttpEntity entity = response.getEntity();  
				String content = EntityUtils.toString(entity, "UTF-8"); 
				Map<String, Object> data = JsonUtil.convertJsonToMap(content);
				throw new CloudFoundryApiException(response.getStatusLine().getStatusCode(), (String) data.get("description"));
			}
		} catch (Exception e) {
			throw e;
		} finally {
			httpPut.abort(); 
	        httpClient.getConnectionManager().shutdown();
	        file.delete();
		}
		file.delete();
		return true;
	}
	
	/**
     * delete buildpack
     * @param buildpack
     * @param session
     * @return true or false
     * @throws Exception 
     */
	public static boolean delete_buildpack(HttpSession session, String buildpack) throws Exception {
		HttpClient httpClient = null;
		HttpDelete httpDelete = null;
		String guid;
		guid = get_buildpack_id(session, buildpack);
		if (guid.isEmpty()) {
			return false;
		}
		try {
			String host = ((URL) session.getAttribute(LoginHandler.TARGET)).toString();
			String urlPath = host + "/v2/buildpacks/" + guid + "?async=false";
			
			httpClient =  new DefaultHttpClient();
			httpDelete = new HttpDelete(urlPath);
			CloudFoundryClientUtil.setAccessHeaders(httpDelete, session);
			HttpResponse response = httpClient.execute(httpDelete);
			if (!HttpStatusUtil.isSuccessStatus(response.getStatusLine().getStatusCode())) {
				HttpEntity entity = response.getEntity();  
				String content = EntityUtils.toString(entity, "UTF-8"); 
				Map<String, Object> data = JsonUtil.convertJsonToMap(content);
				throw new CloudFoundryApiException(response.getStatusLine().getStatusCode(), (String) data.get("description"));
			} 
			
		} catch (Exception e) {
			throw e;
		} finally {
			httpDelete.abort(); 
	        httpClient.getConnectionManager().shutdown();
		}
		return true;
	}
	
	/**
     * get id of a buildpack
     * @param buildpack
     * @param session
     * @return guid
     * @throws Exception 
     */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static String get_buildpack_id(HttpSession session, String buildpack) throws Exception {
		HttpClient httpClient = null;
		HttpGet httpGet = null;
		String guid;
		String urlPath;
		try {
			String host = ((URL) session.getAttribute(LoginHandler.TARGET)).toString();
			urlPath = host + "/v2/buildpacks?q=name%3A" + buildpack;
			httpClient =  new DefaultHttpClient();
			httpGet = new HttpGet(urlPath);
			CloudFoundryClientUtil.setAccessHeaders(httpGet, session);
			HttpResponse response = httpClient.execute(httpGet);
			HttpEntity entity = response.getEntity();  
			String content = EntityUtils.toString(entity, "UTF-8"); 
			Map<String, Object> data = JsonUtil.convertJsonToMap(content);
			if (!HttpStatusUtil.isSuccessStatus(response.getStatusLine().getStatusCode())) {
				throw new CloudFoundryApiException(response.getStatusLine().getStatusCode(),  (String) data.get("description"));
			}
			guid = (String) ((Map<String, Object>) ((Map<String, Object>) ((List) data.get("resources")).get(0)).get("metadata")).get("guid");
		} catch (Exception e) {
			throw e;
		} finally {
	        httpGet.abort(); 
	        httpClient.getConnectionManager().shutdown();
		}
		return guid;
	}
	

}
